package com.basker.pisces.domain.command.meta;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.basker.pisces.core.meta.annotation.DataField;
import com.basker.pisces.domain.ISupportEntityBuild;
import com.basker.pisces.domain.constant.DomainConstants.DataStatus;
import com.basker.pisces.domain.entity.meta.Entity;
import com.basker.pisces.domain.property.meta.Property;
import com.basker.pisces.domain.property.meta.StatusProperty;

/**
 * 删除命令
 *
 * <p>
 * <li>支持假删除，参见属性{@link #getMode()}
 * <li>支持执行前的状态校验，参见属性{@link #getValidStatuses()}
 *
 * @author hangwen
 */
public class DeleteCommand extends TransactionalCommand implements ISupportEntityBuild {

    @DataField
    private DeleteMode mode = DeleteMode.Delete;

    @DataField
    private String statusPropertyAlias;

    @DataField
    private List<Integer> validStatuses = new ArrayList<>();

    public DeleteCommand() {
        this.setName(DeleteCommand.class.getSimpleName());
        this.setRequireReload(true);
    }

    @Override
    public void build(Entity entity) {
        if (DeleteMode.ChangeStatus.equals(this.getMode())) {
            StatusProperty statusProperty = this.findStatusProperty(entity);
            Assert.notNull(statusProperty, "DeleteCommand's Mode is ChangeStatus,but entity has no Status Property");
        }
    }

    /**
     * 获取当前命名对应的删除模式。
     *
     * <p>
     * 如果是{@link DeleteMode#ChangeStatus},会找到当前实体的状态属性，并将属性更新为{@link DataStatus#DELETE}(如果没有状态属性则会抛出异常);
     * 无果是{@link DeleteMode#Delete},则是执行数据层面的删除
     *
     * @return
     */
    public DeleteMode getMode() {
        return mode;
    }

    /**
     * 如果删除模式{{@link #getMode()}}是{@link DeleteMode#ChangeStatus},则需要制定状态属性，如果实体只有一个状态属性，也可以不指定
     *
     * @return
     */
    public String getStatusPropertyAlias() {
        return statusPropertyAlias;
    }

    /**
     * 获取执行删除命令的合法状态
     *
     * <p>
     * 获取当前对象的可以执行命令的合法状态，只有状态与返回值匹配的记录才可以正常删除，如果返回null或者空集合，则不进行有效状态的判断
     *
     * @return
     */
    public List<Integer> getValidStatuses() {
        return validStatuses;
    }

    /**
     * 设置删除模式
     *
     * @param mode
     * @see #getMode()
     */
    public void setMode(DeleteMode mode) {
        this.mode = mode;
    }

    public void setStatusPropertyAlias(String statusPropertyAlias) {
        this.statusPropertyAlias = statusPropertyAlias;
    }

    /**
     * 设置执行删除命令的合法状态
     *
     * @param validStatuses
     * @see #getValidStatuses()
     */
    public void setValidStatuses(List<Integer> validStatuses) {
        this.validStatuses = validStatuses;
    }

    private StatusProperty findStatusProperty(Entity entity) {
        String statusPropertyAlias = this.getStatusPropertyAlias();

        if (StringUtils.isEmpty(statusPropertyAlias)) {
            StatusProperty[] statusProperties = entity.getStatusProperties();
            int length = ArrayUtils.getLength(statusProperties);

            if (length == 1) {
                this.setStatusPropertyAlias(statusProperties[0].getAlias());
                return statusProperties[0];
            }

            return null;
        } else {
            Property<?> property = entity.getPropertyByAlias(statusPropertyAlias);

            if (property instanceof StatusProperty) {
                return (StatusProperty) property;
            }

            return null;
        }
    }

    /**
     * 删除模式
     *
     * @author hangwen
     * @see DeleteCommand#getMode()
     */
    public static enum DeleteMode {
        Delete, ChangeStatus
    }
}
